﻿using System;
using System.Collections.Generic;
using System.Web;

using FireBus.Contracts;
using FireBus.Core;
using FireBus.Web.Contracts;
using HttpRequest = System.Web.HttpRequest;


namespace FireBus.Web.Framework
{
	public class Router
	{
		private readonly Host _Host;

		private readonly IDictionary<ExtensionName, IList<Route>> _Routes
			= new Dictionary<ExtensionName, IList<Route>>();

		private readonly Object _Sync = new Object();


		public Router(Host host)
		{
			if (host == null)
			{
				throw new ArgumentNullException("host");
			}
			_Host = host;

			SubscribeToEvents();
		}

		private void SubscribeToEvents()
		{
			_Host.ExtensionLoaded += OnHostExtensionLoaded;
			_Host.ExtensionUnloaded += OnHostExtensionUnloaded;
		}

		private void OnHostExtensionLoaded(object sender, ExtensionEventArgs e)
		{
			try
			{
				_Host.BeginRequest<RouteListRequest, RouteListResponse>(
					e.Extension, new RouteListRequest(), OnRouteListRequested, e.Extension);
			}
			catch (InvalidRequestException)
			{
			}
		}

		private void OnRouteListRequested(IAsyncResult ar)
		{
			var extensionName = (ExtensionName) ar.AsyncState;
			var routes = _Host.EndRequest<RouteListResponse>(ar);
			lock (_Sync)
			{
				_Routes.Add(
					extensionName, routes.Items);
			}
		}

		private void OnHostExtensionUnloaded(Object sender, ExtensionEventArgs e)
		{
			lock (_Sync)
			{
				_Routes.Remove(e.Extension);
			}
		}

		public ExtensionAction RequestToAction(HttpRequest request)
		{
			if (request == null)
			{
				throw new ArgumentNullException("request");
			}
			lock (_Sync)
			{
				var url = request.Url.AbsolutePath;
				foreach (var pair in _Routes)
				{
					foreach (var route in pair.Value)
					{
						if (route.Pattern == url)
						{
							var action = new ExtensionAction(
								pair.Key,
								route.Action);
							return action;
						}
					}
				}
				return null;
			}
		}
	}
}
